﻿using Newtonsoft.Json;
using Orleans;
using Orleans.Storage;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;

namespace iTool.ClusterComponent
{
    public static partial class iUtils
    {
        readonly static ConcurrentDictionary<Type, object> typeDefaultValueMap = new ConcurrentDictionary<Type, object>();
        readonly static ConcurrentDictionary<string, string> serverKeyTypeMap = new ConcurrentDictionary<string, string>();
        readonly static NewtonJsonSerializerSettings serializerSettings = new NewtonJsonSerializerSettings();
        readonly static object _lock = new object();
        readonly static object _lockdefault = new object();

        public static object DefaultForType(Type targetType)
        {
            if (typeDefaultValueMap.ContainsKey(targetType))
            {
                return typeDefaultValueMap[targetType];
            }

            lock (_lockdefault)
            {
                if (typeDefaultValueMap.ContainsKey(targetType))
                {
                    return typeDefaultValueMap[targetType];
                }
                else
                {
                    var value = targetType.IsValueType ? Activator.CreateInstance(targetType) : null;
                    typeDefaultValueMap.TryAdd(targetType, value);
                    return typeDefaultValueMap[targetType];
                }
            }
        }

        public static string GetKeyTypeOfClass(string className)
        {
            if (serverKeyTypeMap.ContainsKey(className))
            {
                return serverKeyTypeMap[className];
            }

            lock (_lock)
            {
                if (serverKeyTypeMap.ContainsKey(className))
                {
                    return serverKeyTypeMap[className];
                }
                else
                {
                    string keyType = string.Empty;
                    Type type = Type.GetType(className);

                    if (type == null)
                    {
                        serverKeyTypeMap.TryAdd(className, keyType);
                        return serverKeyTypeMap[className];
                    }

                    if (type.GetInterface(nameof(iToolServiceWithIntegerKey)) != null)
                    {
                        keyType = "long";
                    }
                    else if (type.GetInterface(nameof(iToolServiceWithGuidKey)) != null)
                    {
                        keyType = "guid";
                    }
                    else if (type.GetInterface(nameof(iToolServiceWithStringKey)) != null)
                    {
                        keyType = "string";
                    }
                    else if (type.GetInterface(nameof(iToolServiceWithIntegerCompoundKey)) != null)
                    {
                        keyType = "long-string";
                    }
                    else if (type.GetInterface(nameof(iToolServiceWithGuidCompoundKey)) != null)
                    {
                        keyType = "guid-string";
                    }

                    serverKeyTypeMap.TryAdd(className, keyType);
                    return serverKeyTypeMap[className];
                }
            }
        }

        public static string SerializeObject(object value) 
        {
            if (value == null)
                return string.Empty;

            return JsonConvert.SerializeObject(value, serializerSettings.Create());
        }

        public static T DeserializeObject<T>(string value)
        {
            if (string.IsNullOrEmpty(value))
                return default(T);

            return JsonConvert.DeserializeObject<T>(value,  serializerSettings.Create());
        }

        public static object DeserializeObject(string value, Type type)
        {
            if (string.IsNullOrEmpty(value))
                return DefaultForType(type);

            return JsonConvert.DeserializeObject(value, type, serializerSettings.Create());
        }

        public static Guid ToGuid(string input)
        {
            using (MD5 md5Hash = MD5.Create())
            {
                var computehash = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
                return new Guid(computehash);
                //data = BitConverter.ToString(computehash, 4, 8);
                //data = data.Replace("-", "");
            }

            //Encoding.Default.GetBytes(data).CopyTo(bytes, 0);
            //return new Guid(bytes);
        }
    }
}
